Go Programming - Basics
Concepts of Programming Languages
Sebastian Macke
Rosenheim Technical University
Sebastian Macke
Rosenheim Technical University
-- Miro Board ....
2// Ints are allowed to return int returnint() { return 1; } // Structs are allowed to return typedef struct{} structdef; structdef returnstruct() { structdef mystruct; return mystruct; } // Arrays are not allowed to return int[3] returnarray() { static int myarray[3] = {1, 2, 3}; return myarray; }
-- Go doesn't allow this operation.
-- In Go, there is only one loop: for
int x; // x is a value MyClass y; // y is a reference
-- Go has pointers and values. But the way they are stored is the same.
7go env Print Go environment information
go run file.go just runs the code. Can be multiple files, too.
go build downloads dependencies and builds the executable, but needs a go.mod file.
go tool dist list list all supported platforms
env GOOS=darwin GOARCH=arm64 go build Build for Apple ARM CPU computers.
go fmt formats your files
go mod init creates a go.mod module file
go mod tidy updates the go mod file if you add more dependencies
10package main import ( "fmt" ) func main() { fmt.Printf("Hello %s", "Programming with Go \xE2\x98\xAF\n") // \xE2\x98\xAF -> ☯ fmt.Printf("Hello %s", "Programming with Go ☯\n") }
Golang | Java | Comment |
---|---|---|
bool | boolean | |
string | String | |
int | machine-sized in Go | |
int8 | byte | |
int16 | short | |
int32 | int | |
int64 | long | |
uint | - | unsigned int |
uint8 | - | |
uint16 | - | |
uint32 | - | |
uint64 | - | |
uintptr | - | |
byte | - | alias for uint8 |
rune | char | alias for int32, represents a Unicode code point. In Java usually 2 bytes. |
float32 | float | |
float64 | double | |
complex64 // complex | ||
complex128 | ||
struct {x,z,y int} | class |
package main import ( "fmt" "math/cmplx" ) func main() { c := 3 + 4i fmt.Printf("c=%v\n", c) r, θ := cmplx.Polar(c) // Go supports variables with unicode characters fmt.Printf("r=%v, θ=%v\n", r, θ) }
Languages differ of how serious they handle the type
Go uses a strong typing system. But why?
16int main() { signed int a = -1; unsigned int b = 0; if (a < b) { printf("a ís smaller than b\n"); } return 0; }
Also: Change int to char
17package main import "fmt" func main() { var a int32 = -1 var b uint32 = 2 if a < int32(b) { fmt.Printf("a is smaller than b") } }
var foo int // default value zero foo = 32 var foo int = 32 var foo = 32 foo := 32 // infers (guesses) the type definition of type int foo := int(32) foo, ok := 32, true // foo is an int 32, ok is a boolean with value true
func PrintVariableDetails(v any) { typeof := reflect.TypeOf(v) fmt.Printf("The variable with type '%s' has the value '%v'\n", typeof.Name(), v) } func main() { var someValue any someValue = 2 PrintVariableDetails(someValue) someValue = "abcd" PrintVariableDetails(someValue) if tmp, ok := someValue.(string); ok { fmt.Println("someValue is a string and has the value", tmp) } }
package main import "fmt" func main() { m := make(map[string]string) // Initialize an empty map m["foo"] = "bar" // insert a key-value pair into map value, ok := m["asd"] // check if key is present, return parameters can be ignored with "_" fmt.Println(ok, value) // returns false, value is just an empty string "" value, ok = m["foo"] // returns true, value contains "bar" fmt.Println(ok, value) for k, v := range m { fmt.Println(k, v) } }
append()
)package main import "fmt" func main() { arr := [5]int{1, 2, 3, 4, 5} // create fixed array fmt.Println(arr) s := arr[0:2] // create a slice out of the array. Otherwise via "make([2]int)" for a new array fmt.Println(s) fmt.Println(len(s), cap(s)) // ==> 2, 5 s[0] = 100 // a slice is just a reference fmt.Println(arr) s = append(s, 8) s = append(s, 9) s = append(s, 10) s = append(s, 11) fmt.Println(len(s), cap(s)) // ==> 6, 10 fmt.Println(arr) }
// IsPalindrome implementation. Does only work for 1-Byte UTF-8 chars (ASCII). func IsPalindrome(word string) bool { for pos := 0; pos < len(word)/2; pos++ { if word[pos] != word[len(word)-pos-1] { return false } } return true }
// palindrome_test.go func TestPalindrome(t *testing.T) { if !IsPalindrome("") { t.Error("isPalindrome('' should be true. But is false.") } if !IsPalindrome("o") { t.Error("isPalindrome('o' should be true. But is false.") } if !IsPalindrome("oto") { t.Error("isPalindrome('oto' should be true. But is false.") } if IsPalindrome("ottos") { t.Error("isPalindrome('ottos' should be false. But is true.") } }
// IsPalindrome2 is using runes. This works for all UTF-8 chars (SBC, MBC). func IsPalindrome2(word string) bool { var runes = []rune(word) for pos, ch := range runes { if ch != runes[len(runes)-pos-1] { return false } } return true }
[]rune(string)
converts a string into a slice of runespos, ch := range runes
// IsPalindrome3 is implemented by reusing Reverse(). Reverse works for UTF-8 chars. func IsPalindrome3(word string) bool { return strings.Reverse(word) == word }
A pointer is a variable which contains a memory address
func main() { num := 42 // implicit type "int" with value 42 ptr := &num // implicit type of "pointer to type int points to num" //var num int = 42 // explicit type definition //var ptr *int = &num // explicit type definition fmt.Println("Value of num:", num) // Expected Output: Value of num: 42 fmt.Println("Address of num:", &num) // Expected Output: Address of num: 0xSOME_MEMORY_ADDRESS (this will vary every run) fmt.Println("Address stored in ptr:", ptr) // Expected Output: Address stored in ptr: 0xSOME_MEMORY_ADDRESS (same as address of num) fmt.Println("Value via pointer:", *ptr) // Expected Output: Value via pointer: 42 *ptr = 43 fmt.Println("Value of num:", num) // Expected output: New value in num = 43 }
func swap0(x, y int) (int, int) { return y, x }
func swap1(x, y int) { x, y = y, x }
func swap2(x *int, y *int) { *x, *y = *y, *x }
func swap3(x **int, y **int) { *x, *y = *y, *x }
func main() { var a, b = 1, 2 fmt.Printf("Initial : a=%d, b=%d\n", a, b) a, b = b, a fmt.Printf("After a,b = b,a : a=%d, b=%d\n", a, b) swap0(a, b) fmt.Printf("After swap0(a,b) : a=%d, b=%d\n", a, b) a, b = swap0(a, b) fmt.Printf("After a,b = swap0(a,b) : a=%d, b=%d\n", a, b) swap1(a, b) fmt.Printf("After swap1(a,b) : a=%d, b=%d\n", a, b) swap2(&a, &b) fmt.Printf("After swap2(&a,&b) : a=%d, b=%d\n", a, b) pa, pb := &a, &b swap3(&pa, &pb) fmt.Printf("After swap3(&pa, &pb): a=%d, b=%d, *pa=%v, *pb=%v\n", a, b, *pa, *pb) }
github.com/s-macke/concepts-of-programming-languages/blob/master/docs/exercises/Exercise2.1.md
36func main() { z := [2]int64{10, 20} // fixed size array y := &z[0] // pointer to first entry in array fmt.Println(y) y = (*int64)(unsafe.Add(unsafe.Pointer(y), 8)) // 64 Bit has 8 bytes fmt.Println(y) *y = 30 // changes second parameter in the array z fmt.Println(z) }
Types can be defined with the keyword "type"
// Page contains an array of words. type Page []string // Book is an array of pages. type Book []Page // Index contains a list of pages for each word in a book. type Index map[string][]int // MakeIndex generates an index structure func MakeIndex(book Book) Index { .... }
package main import ( "fmt" "strings" ) type Page []string func (p Page) String() string { return strings.Join(p, "\n") } func main() { page := Page{"This is the first paragraph", "This is the second paragraph"} fmt.Println(page) }
import ( "flag" "fmt" ) // Simple test for the Go flag API. func main() { // construct a string flag with a default ip address and a description. ip := flag.String("ip", "192.168.1.1", "Overrides the default IP address.") port := flag.String("port", "8080", "Overrides the default listen port.") flag.Parse() fmt.Println("\nDefault value for IP: " + *ip) fmt.Println("\nDefault value for port: " + *port) }
github.com/s-macke/concepts-of-programming-languages/blob/master/docs/exercises/Exercise2.2.md
42